package com.well.register.netty.handle;

import com.well.register.event.AppEvent;
import com.well.register.event.EventContext;
import com.well.register.event.RegisterEvent;
import com.well.register.event.ServerHandler;
import com.well.register.util.ThreadUtils;
import com.well.rpc.model.EventType;
import com.well.rpc.model.TransData;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Server channel Handler
 */
public class ServerEventHandler extends SimpleChannelInboundHandler<TransData> {

    Logger logger = LoggerFactory.getLogger(this.getClass());
    private int unRecPingTimes = 0;
    /*Over times */
    private static final int MAX_UN_REC_PING_TIMES = 3;
    private SslContext sslContext;

    public ServerEventHandler(SslContext sslContext) {
//        this.sslContext = sslContext;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
//        ctx.pipeline().get(SslHandler.class).handshakeFuture()
//                .addListener((GenericFutureListener<Future<Channel>>) arg0 -> {
//                    if (!arg0.isSuccess()) {
//                        ServerHandler.exception(ctx, "handshake fail");
//                    }
//                });
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TransData transData) throws Exception {
        AppEvent eventByType = EventContext.getEventByType(transData.getType());
        if (eventByType == null) {
            logger.error("no have this connect type !");
            channelHandlerContext.writeAndFlush("no have this connect type !");
            channelHandlerContext.close();
            return;
        }
        ThreadUtils.execute(() -> {
            eventByType.doEvent(channelHandlerContext, transData);
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error(cause.getMessage());
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                if (unRecPingTimes >= MAX_UN_REC_PING_TIMES) {
                    logger.info("READER_IDLE read over time,Close channel");
                    ctx.close();
                } else {
                    unRecPingTimes++;
                }
            } else {
                super.userEventTriggered(ctx, evt);
            }
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        RegisterEvent registerEvent = (RegisterEvent) EventContext.getEventByType(EventType.REGISTER);
        registerEvent.serverDown(ctx);
    }
}
